#(Vindictus) MDL parser

import os, sys
from Sanae3D.lib.ModelObject import Model3D
from Sanae3D.lib.StructReader import StructReader

class Vindictus_MDL(Model3D):
    
    MAX_NUM_LOD = 8
    MAX_NUM_BONES_PER_VERT = 3
    
    def __init__(self, obj3D=None, outFile=None, inFile=None):
        
        super(Vindictus_MDL,self).__init__("MDL")
        self.obj3D = obj3D
        self.inFile = inFile
        self.outFile = outFile
        self.vvdFile = None
        self.vtxFile = None
        self.vertNums = []
        self.filename = ""
        self.path = ""
        
    def read_name(self):
        
        name = ""
        char = self.inFile.read_char()
        while char != "\x00":
            name = ''.join([name, char])
            char = self.inFile.read_char()
        return name
        
    #=== VTX file ===
    
    def parse_faces(self, numFaces, meshName):
        
        for i in range(numFaces):
            v1, v2, v3 = self.vtxFile.read_short(3)
            
            v1, v2, v3 = self.vertNums[v1], self.vertNums[v2], self.vertNums[v3]
            self.create_face(meshName, i)
            self.add_face_verts(meshName, i, [v1, v2, v3])
    
    def parse_vertex_table(self, numVerts, tableStart):
        
        self.vtxFile.seek(tableStart, 1)
        for i in range(numVerts):
            unk1 = self.vtxFile.read_byte(4)
            vertNum = self.vtxFile.read_short()
            unk2 = self.vtxFile.read_byte(3)
            self.vertNums.append(vertNum)

    def parse_vtx(self, numLOD):
        '''Parse vtx file'''
        
        try:
            vtxName = ''.join([self.path, '.dx90.vtx'])
            self.vtxFile = StructReader(open(vtxName, 'rb'))
        except:
            try:
                vtxName = ''.join([self.path, '.dx80.vtx'])
                self.vtxFile = StructReader(open(vtxName, 'rb'))
            except:
                print "Couldn't find ", vtxName
                return
        version, vertCacheSize = self.vtxFile.read_long(2)
        maxBonesPerStrip, maxBonesPerTri = self.vtxFile.read_short(2)
        maxBonesPerVert = self.vtxFile.read_long()
        checksum = self.vtxFile.read_long()
        numLOD, matReplaceListOffset, numBodyParts, \
              bodyPartOffset = self.vtxFile.read_long(4)
        
        self.vtxFile.seek(37, 1)
        numVerts, vertTableOffset, numFaces, faceOffset, \
                unkOff1, unkOff2 = self.vtxFile.read_long(6)
        unkbyte = self.inFile.read_byte()
        
        self.parse_vertex_table(numVerts, vertTableOffset - 24)
        
        for i in range(numLOD):
            meshName = "%s[%d]" %(self.filename, i)
            self.parse_faces(numFaces / 3, meshName)
        
    #=== VVD file ===
    
    def parse_vertices(self, numVerts, vertStart, meshName):
        
        self.vvdFile.seek(vertStart)
        for i in range(numVerts):
            weights = self.vvdFile.read_float(self.MAX_NUM_BONES_PER_VERT)
            bones = self.vvdFile.read_char(self.MAX_NUM_BONES_PER_VERT)
            numBones = self.vvdFile.read_byte()
            
            vx, vy, vz = self.vvdFile.read_float(3)
            nx, ny, nz = self.vvdFile.read_float(3)
            tu, tv = self.vvdFile.read_float(2)
            
            vx = float(vx) * -1.0
            
            self.create_vertex(meshName, i)
            self.add_coords(meshName, i, [vx, vz, vy])
            self.add_vert_uv(meshName, i, [tu, tv])
            self.add_vert_normals(meshName, i, [nx, ny, nz])
    
    def parse_vvd(self):
        '''parse vvd file'''
        
        try:
            vvdName = ''.join([self.path, '.vvd'])
            self.vvdFile = StructReader(open(vvdName, 'rb'))
        except:
            print "Couldn't find ", vvdName
            return
        
        idString = self.vvdFile.read_string(4)
        version, checkSum = self.vvdFile.read_long(2)
        numLOD = self.vvdFile.read_long()
        numVerts = self.vvdFile.read_long(self.MAX_NUM_LOD)[0]
        numFixUp, fixUpStart, vertDataStart, \
                tangentDataStart = self.vvdFile.read_long(4)
        
        for i in range(numLOD):
            meshName = "%s[%d]" %(self.filename, i)
            self.create_object(meshName)
            self.parse_vertices(numVerts, vertDataStart, meshName)
        return numLOD
    
    #=== MDL File ===
    
    def parse_textures(self, texOffset):
        
        self.inFile.seek(texOffset)      
        nameOffset, flags, used, unused, mat, clientMat \
                  = self.inFile.read_long(6)
        self.inFile.seek(40, 1)
    
        #get name
        curPos = self.inFile.tell()
        self.inFile.seek(texOffset + nameOffset)
        texName = ''.join([self.read_name(), ".vmt"])
        self.inFile.seek(curPos)
        #
        
        #print texName 

    def parse_file(self, path):
        '''Main parser method. Can be replaced'''
        
        self.path = os.path.splitext(path)[0]
        self.filename = os.path.basename(self.path)
        
        magic = self.inFile.read_string(4)
        version = self.inFile.read_long()
        self.inFile.seek(4, 1) #???
        name = self.inFile.read_string(64).strip("\x00")
        totalSize = self.inFile.read_long()
        
        eyePosition = self.inFile.read_float(3)
        illumPosition = self.inFile.read_float(3)
        hull_min = self.inFile.read_float(3)
        hull_max = self.inFile.read_float(3)
        bbMin = self.inFile.read_float(3)
        bbMax = self.inFile.read_float(3)
        
        flags = self.inFile.read_long()       
        numBones, boneOffset = self.inFile.read_long(2)
        numBoneControl, boneControlOffset = self.inFile.read_long(2)
        numHitBox, hitBoxOffset = self.inFile.read_long(2)
        numLocalAnim, localAnimOffset = self.inFile.read_long(2)
        numLocalSeq, localSeqOffset = self.inFile.read_long(2)
        activityListVersion, eventsIndexed = self.inFile.read_long(2)
        
        numTex, texOffset = self.inFile.read_long(2)
        numTexDir, texDirOffset = self.inFile.read_long(2)
        
        numSkinRef, skinRefFamily, skinRefOffset = self.inFile.read_long(3)        
        self.inFile.seek(176, 1)
        
        numLOD = self.parse_vvd()
        self.parse_vtx(numLOD)
        self.parse_textures(texOffset)
        
        print numSkinRef, skinRefFamily, skinRefOffset
        
def read_file(path):
    '''Read the file'''    
    
    openFile = StructReader(open(path, 'rb'))
    obj = Vindictus_MDL(inFile=openFile)
    obj.parse_file(path)
    openFile.close()
    return obj

def write_file(path):
    
    pass

def definitions():
    '''Return the header, extension, and a description of the format'''
    
    return "IDST", "MDL", "Vindictus MDL"

if __name__ == '__main__':
    
    file1 = "barbecue_set.mdl"
    obj = read_file(file1)